﻿using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

namespace UtilZ.Dotnet.Ex.Model
{
#pragma warning disable 8500

    /// <summary>
    /// IQ值类型柔性数组
    /// </summary>
    unsafe public partial class IQValueTypeFlexibleArray<T>
    {
        private void ReallocArray(int length)
        {
            if (length <= 0)
            {
                throw new ArgumentOutOfRangeException(nameof(length), $"元数个数不能小于0,值\"{length}\"无效.");
            }

            if (this.IsReferenced())
            {
                throw new InvalidOperationException("当前数组模式为引用模式,不允许对内存大小进行调整操作.");
            }

            if (this._capcity < length)
            {
                void* newIDataPtr, newQDataPtr;
                var byteCount = (nuint)(length * sizeof(T));
                if (this._capcity == 0)
                {
                    newIDataPtr = NativeMemory.Alloc(byteCount);
                    newQDataPtr = NativeMemory.Alloc(byteCount);
                }
                else
                {
                    newIDataPtr = NativeMemory.Realloc(this._iDataPtr, byteCount);
                    newQDataPtr = NativeMemory.Realloc(this._qDataPtr, byteCount);
                }

                if (newIDataPtr == null)
                {
                    if (newQDataPtr == null)
                    {
                        throw new AccessViolationException($"I路和Q路申请大小为{byteCount}Byte的内存失败.");
                    }
                    else
                    {
                        NativeMemory.Free(newQDataPtr);
                        throw new AccessViolationException($"I路申请大小为{byteCount}Byte的内存失败.");
                    }
                }
                else
                {
                    if (newQDataPtr == null)
                    {
                        NativeMemory.Free(newIDataPtr);
                        throw new AccessViolationException($"Q路申请大小为{byteCount}Byte的内存失败.");
                    }
                    else
                    {
                        this._iDataPtr = (T*)newIDataPtr;
                        this._qDataPtr = (T*)newQDataPtr;
                        this._capcity = length;
                    }
                }
            }
        }

        /// <summary>
        /// 清除当前对象数据指针指向的内容
        /// </summary>
#if !NET4_0
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
        public void Clear()
        {
            if (this._capcity != 0)
            {
                NativeMemory.Clear(this._iDataPtr, (nuint)(this._capcity * sizeof(T)));
                NativeMemory.Clear(this._qDataPtr, (nuint)(this._capcity * sizeof(T)));
            }
        }


        /// <summary>
        /// Copies the contents of this span into a new array.  This heap
        /// allocates, so should generally be avoided, however it is sometimes
        /// necessary to bridge the gap with APIs written in terms of arrays.
        /// </summary>
#if !NET4_0
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
        public T[] ToArrayI()
        {
            if (this._length <= 0)
            {
#if NET4_0
                return UtilZ.Dotnet.Ex.Base.ArrayEx.Empty<T>();
#else
                return Array.Empty<T>();
#endif
            }

            var destination = new T[this._length];
            fixed (T* dstPtr = destination)
            {
                NativeMemory.Copy(this._iDataPtr, dstPtr, (nuint)(this._length * sizeof(T)));
            }

            return destination;
        }

        /// <summary>
        /// Copies the contents of this span into a new array.  This heap
        /// allocates, so should generally be avoided, however it is sometimes
        /// necessary to bridge the gap with APIs written in terms of arrays.
        /// </summary>
#if !NET4_0
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
        public T[] ToArrayQ()
        {
            if (this._length <= 0)
            {
#if NET4_0
                return UtilZ.Dotnet.Ex.Base.ArrayEx.Empty<T>();
#else
                return Array.Empty<T>();
#endif
            }

            var destination = new T[this._length];
            fixed (T* dstPtr = destination)
            {
                NativeMemory.Copy(this._qDataPtr, dstPtr, (nuint)(this._length * sizeof(T)));
            }

            return destination;
        }





        /// <summary>
        /// 将当前数据复制到目标数据中,作参数检查
        /// </summary>
        /// <param name="destination">目标数据</param>
        /// <returns>拷贝数据长度</returns>
#if !NET4_0
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
        public int CopyTo(IQValueTypeFlexibleArray<T> destination)
        {
            if (this._length > destination._length)
            {
                throw new ArgumentOutOfRangeException("目标长度不足");
            }

            int copyCount = Math.Min(this._length, destination.Length);
            var byteCount = (nuint)(copyCount * sizeof(T));
            NativeMemory.Copy(this._iDataPtr, destination._iDataPtr, byteCount);
            NativeMemory.Copy(this._qDataPtr, destination._qDataPtr, byteCount);
            return copyCount;
        }

        /// <summary>
        /// 将当前数据复制到目标数据中,作参数检查
        /// </summary>
        /// <param name="startIndex">当前数据起始位置</param>
        /// <param name="destination">目标数据</param>
        /// <param name="destinationStartIndex">目标数据起始位置</param>
        /// <param name="count">复制元素个数</param>
        /// <returns>拷贝数据长度</returns>
#if !NET4_0
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
        public int CopyTo(int startIndex, IQValueTypeFlexibleArray<T> destination, int destinationStartIndex, int count)
        {
            if (count < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(startIndex), $"要拷贝的数据长度{count}无效,该值不能小于0.");
            }

            if (startIndex < 0 || startIndex + count > this._length)
            {
                throw new ArgumentOutOfRangeException(nameof(startIndex), $"起始索引值{startIndex}无效或数据长度{count}无效,该值不能小于0或大于当前数据长度{this._length}.");
            }

            if (destinationStartIndex < 0 || destinationStartIndex + count > destination._length)
            {
                throw new ArgumentOutOfRangeException(nameof(startIndex), $"目标索引值{startIndex}无效或数据长度{count}无效,该值不能小于0或大于目标数据长度{destination._length}.");
            }

            var availableLen = this._length - startIndex;
            int copyCount = Math.Min(count, availableLen);
            var byteCount = (nuint)(copyCount * sizeof(T));
            NativeMemory.Copy(this._iDataPtr + startIndex, destination._iDataPtr + destinationStartIndex, byteCount);
            NativeMemory.Copy(this._qDataPtr + startIndex, destination._qDataPtr + destinationStartIndex, byteCount);
            return copyCount;
        }

        /// <summary>
        /// 将数据拷贝到目标指针数据中,作参数检查
        /// </summary>
        /// <param name="destinationIPtr">目标I路数据指针</param>
        /// <param name="destinationQPtr">目标Q路数据指针</param>
        /// <param name="count">指针数据元素个数</param>
        /// <returns>拷贝数据长度</returns>
        /// <exception cref="ArgumentOutOfRangeException">参数越界异常</exception>
#if !NET4_0
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
        public int CopyTo(T* destinationIPtr, T* destinationQPtr, int count)
        {
            if (count < 0 || count > this._length)
            {
                throw new ArgumentOutOfRangeException(nameof(count), $"目标长度{count}大于源长度{this._length - count}.");
            }

            int copyCount = Math.Min(count, this._length);
            nuint byteCount = (nuint)(copyCount * sizeof(T));
            NativeMemory.Copy(this._iDataPtr, destinationIPtr, byteCount);
            NativeMemory.Copy(this._qDataPtr, destinationQPtr, byteCount);
            return copyCount;
        }

        /// <summary>
        /// 将数据拷贝到目标指针数据中,作参数检查
        /// </summary>
        /// <param name="startIndex">当前数据起始位置</param>
        /// <param name="destinationIPtr">目标I路数据指针</param>
        /// <param name="destinationQPtr">目标Q路数据指针</param>
        /// <param name="count">指针数据元素个数</param>
        /// <returns>拷贝数据长度</returns>
        /// <exception cref="ArgumentOutOfRangeException">参数越界异常</exception>
#if !NET4_0
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
        public int CopyTo(int startIndex, T* destinationIPtr, T* destinationQPtr, int count)
        {
            if (count < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(startIndex), $"要拷贝的数据长度{count}无效,该值不能小于0.");
            }

            if (startIndex < 0 || startIndex + count > this._length)
            {
                throw new ArgumentOutOfRangeException(nameof(startIndex), $"起始索引值{startIndex}无效,该值不能小于0或大于当前数据长度{this._length}.");
            }

            var availableLen = this._length - startIndex;
            int copyCount = Math.Min(count, availableLen);
            nuint byteCount = (nuint)(copyCount * sizeof(T));
            NativeMemory.Copy(this._iDataPtr + startIndex, destinationIPtr, byteCount);
            NativeMemory.Copy(this._qDataPtr + startIndex, destinationQPtr, byteCount);
            return copyCount;
        }

        /// <summary>
        /// 将数据拷贝到目标数据中,作参数检查
        /// </summary>
        /// <param name="destination">目标数据</param>
        /// <exception cref="ArgumentOutOfRangeException">参数越界异常</exception>
#if !NET4_0
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
        public int CopyTo(IQSpanZ<T> destination)
        {
            if (destination.Length > this._length)
            {
                throw new ArgumentOutOfRangeException($"目标长度{destination.Length}大于源长度{this._length}.");
            }

            int copyCount = Math.Min(this._length, destination.Length);
            nuint byteCount = (nuint)(copyCount * sizeof(T));
            NativeMemory.Copy(this._iDataPtr, destination.IDataPtr, byteCount);
            NativeMemory.Copy(this._qDataPtr, destination.QDataPtr, byteCount);
            return copyCount;
        }

        /// <summary>
        /// 将数据拷贝到目标数据中,作参数检查
        /// </summary>
        /// <param name="startIndex">当前数据起始位置</param>
        /// <param name="destination">目标数据</param>
        /// <returns>拷贝数据长度</returns>
        /// <exception cref="ArgumentOutOfRangeException">参数越界异常</exception>
#if !NET4_0
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
        public int CopyTo(int startIndex, IQSpanZ<T> destination)
        {
            if (startIndex < 0 || startIndex > this._length)
            {
                throw new ArgumentOutOfRangeException(nameof(startIndex), $"起始索引值{startIndex}无效,该值不能小于0或大于当前数据长度{this._length}.");
            }

            int count = this._length - startIndex;
            if (count > destination.Length)
            {
                throw new ArgumentOutOfRangeException(nameof(destination.Length), $"目标长度{destination.Length}小于源长度{count}.");
            }

            int copyCount = Math.Min(count, destination.Length);
            nuint byteCount = (nuint)(copyCount * sizeof(T));
            NativeMemory.Copy(this._iDataPtr + startIndex, destination.IDataPtr, byteCount);
            NativeMemory.Copy(this._qDataPtr + startIndex, destination.QDataPtr, byteCount);
            return copyCount;
        }





        /// <summary>
        /// 从指针数据源中将数据复制到当前数组中,作参数检查
        /// </summary>
        /// <param name="sourceIDataPtr">I路指针数据源</param>
        /// <param name="sourceQDataPtr">Q路指针数据源</param>
        /// <param name="count">从指针数据源中复制的元素个数</param>
        /// <exception cref="ArgumentOutOfRangeException">参数越界异常</exception>
#if !NET4_0
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
        public void CopyFrom(T* sourceIDataPtr, T* sourceQDataPtr, int count)
        {
            if (count > this._length)
            {
                throw new ArgumentOutOfRangeException($"源长度{count}大于目标长度{this._length}不足");
            }

            var byteCount = (nuint)(count * sizeof(T));
            NativeMemory.Copy(sourceIDataPtr, this._iDataPtr, byteCount);
            NativeMemory.Copy(sourceQDataPtr, this._qDataPtr, byteCount);
        }

        /// <summary>
        /// 从数据源中将数据复制到当前数组中,作参数检查
        /// </summary>
        /// <param name="source">数据源</param>
        /// <exception cref="ArgumentOutOfRangeException">参数越界异常</exception>
#if !NET4_0
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
        public void CopyFrom(IQSpanZ<T> source)
        {
            if (source.Length > this._length)
            {
                throw new ArgumentOutOfRangeException($"源长度{source.Length}大于目标长度{this._length}不足");
            }

            var byteCount = (nuint)(source.Length * sizeof(T));
            NativeMemory.Copy(source.IDataPtr, this._iDataPtr, byteCount);
            NativeMemory.Copy(source.QDataPtr, this._qDataPtr, byteCount);
        }




        /// <summary>
        /// 
        /// </summary>
        /// <exception cref="NotImplementedException"></exception>
        public void Dispose()
        {
            if (this._disposed)
            {
                return;
            }
            this._disposed = true;

            if (this.IsReferenced())
            {
                return;
            }

            NativeMemory.Free(this._iDataPtr);
            this._iDataPtr = null;

            NativeMemory.Free(this._qDataPtr);
            this._qDataPtr = null;

            this._length = 0;
            this._capcity = 0;
        }

    }
}
